/* **********************************************************************************
 *
 * Copyright (c) TMF.AscendedThemeKit.Unthemed.NET Project. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for TMF.AscendedThemeKit.Unthemed. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for TMF.AscendedThemeKit.Unthemed, please send an email to ascendlic@<TBD>.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for TMF.AscendedThemeKit.Unthemed.NET.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

namespace TMF.AscendedThemeKit.Unthemed
{
    /// <summary>
    /// Represents corner radius information associated with a user interface (UI) element.
    /// </summary>
    [StructLayout(LayoutKind.Sequential), TypeConverter(typeof(CornerRadiusConverter))]
    public struct CornerRadius
    {
        /// <summary>
        /// Provides a CornerRadius object with no radius.
        /// </summary>
        public static readonly CornerRadius Empty;

        private bool _all;
        private int _bottomLeft;
        private int _bottomRight;
        private int _topLeft;
        private int _topRight;

        /// <summary>
        /// Initializes a new instance of the CornerRadius class using the supplied radius size for all corners.
        /// </summary>
        /// <param name="all">System.Int32. The number of pixels to be used the radius for all corners.</param>
        /// <remarks>
        /// This constructor sets the BottomLeft, BottomRight, TopLeft, TopRight and All properties to the value of the all parameter.
        /// </remarks>
        public CornerRadius(int all)
        {
            this._all = true;

            this._bottomLeft = all;
            this._bottomRight = all;
            this._topLeft = all;
            this._topRight = all;

        }

        /// <summary>
        /// Initializes a new instance of the CornerRadius class using the supplied radius sizes for the corners.
        /// </summary>
        /// <param name="bottomLeft">System.Int32. The radius size, in pixels, for the bottom left corner.</param>
        /// <param name="bottomRight">System.Int32. The radius size, in pixels, for the bottom right corner.</param>
        /// <param name="topLeft">System.Int32. The radius size, in pixels, for the top left corner.</param>
        /// <param name="topRight">System.Int32. The radius size, in pixels, for the top right corner.</param>
        /// <remarks>
        /// This constructor sets the BottomLeft, BottomRight, TopLeft, TopRight properties. If the parameters are all the same the All parameter is also set to the value.
        /// </remarks>
        public CornerRadius(int bottomLeft, int bottomRight, int topLeft, int topRight)
        {
            this._bottomLeft = bottomLeft;
            this._bottomRight = bottomRight;
            this._topLeft = topLeft;
            this._topRight = topRight;

            this._all = (!(this._bottomLeft != this._bottomRight) && !(this._bottomLeft != this._topLeft)) && (this._bottomLeft == this._topRight);

        }

        /// <summary>
        /// Gets or sets the radius value for all the corners.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Int32 . The radius, in pixels, for all corners if the same; otherwise, -1.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        public int All
        {
            get
            {
                if (!this._all)
                {
                    return -1;

                }

                return this._bottomLeft;

            }

            set
            {
                if (this._all && (this._bottomLeft == value))
                {
                    return;

                }

                this._all = true;

                this._bottomLeft = value;
                this._bottomRight = value;
                this._topLeft = value;
                this._topRight = value;

            }

        }

        /// <summary>
        /// Gets or sets the radius value for the bottom left corner.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Int32 . The radius, in pixels, for the bottom left corner.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        /// <remarks>
        /// Setting this value can also alter the All property.
        /// </remarks>
        [RefreshProperties(RefreshProperties.All)]
        public int BottomLeft
        {
            get
            {
                return this._bottomLeft;

            }

            set
            {
                this._bottomLeft = value;

            }

        }

        /// <summary>
        /// Gets or sets the radius value for the bottom right corner.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Int32 . The radius, in pixels, for the bottom right corner.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        /// <remarks>
        /// Setting this value can also alter the All property.
        /// </remarks>
        [RefreshProperties(RefreshProperties.All)]
        public int BottomRight
        {
            get
            {
                return this._bottomRight;

            }

            set
            {
                this._bottomRight = value;

            }

        }

        /// <summary>
        /// Gets or sets the radius value for the top left corner.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Int32 . The radius, in pixels, for the left corner.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        /// <remarks>
        /// Setting this value can also alter the All property.
        /// </remarks>
        [RefreshProperties(RefreshProperties.All)]
        public int TopLeft
        {
            get
            {
                return this._topLeft;

            }

            set
            {
                this._topLeft = value;

            }

        }

        /// <summary>
        /// Gets or sets the radius value for the top right corner.
        /// </summary>
        /// <value>
        /// <para>
        /// System.Int32 . The radius, in pixels, for the top right corner.
        /// </para>
        /// <para>
        /// This property is read/write. 
        /// </para>
        /// </value>
        /// <remarks>
        /// Setting this value can also alter the All property.
        /// </remarks>
        [RefreshProperties(RefreshProperties.All)]
        public int TopRight
        {
            get
            {
                return this._topRight;

            }

            set
            {
                this._topRight = value;

            }

        }

        /// <summary>
        /// Returns if the All property has been used.
        /// </summary>
        /// <returns>True or false</returns>
        public bool ShouldSerializeAll()
        {
            return this._all;

        }

        /// <summary>
        /// Determines whether the specified object is equal to the current Object.
        /// </summary>
        /// <param name="obj">The Object to compare with the current Object.</param>
        /// <returns>true if the specified Object is equal to the current Object; otherwise, false.</returns>
        public override bool Equals(object obj)
        {
            if (obj is CornerRadius)
            {
                CornerRadius cornerRadius = (CornerRadius)obj;
                if (((cornerRadius._all == this._all) && (cornerRadius._bottomLeft == this._bottomLeft)) && ((cornerRadius._bottomRight == this._bottomRight) && (cornerRadius._topLeft == this._topLeft)))
                {
                    return (cornerRadius._topRight == this._topRight);

                }

            }

            return false;

        }

        /// <summary>
        /// Serves as a hash function for the border type, suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// <para>
        /// System.Int32
        /// </para>
        /// <para>
        /// A hash code for the CornerRadius object.
        /// </para>
        /// </returns>
        public override int GetHashCode()
        {
            return (((this.BottomLeft ^ RotateLeft(this.BottomRight, 8)) ^ RotateLeft(this.TopLeft, 0x10)) ^ RotateLeft(this.TopRight, 0x18));

        }

        /// <summary>
        /// Returns a string that contains the radius values for an instance of the CornerRadius class.
        /// </summary>
        /// <returns>
        /// <para>
        /// System.String . 
        /// </para>
        /// <para>
        /// A String that represents the current CornerRadius.
        /// </para>
        /// </returns>
        /// <remarks>
        /// <para>
        /// This method returns a string containing the labeled values of the radius for all four corners.
        /// </para>
        /// <para>
        /// This method overrides ToString.
        /// </para>
        /// </remarks>
        public override string ToString()
        {
            StringBuilder returnString = new StringBuilder();
            returnString.Append(this.BottomLeft.ToString(CultureInfo.CurrentCulture.NumberFormat));
            returnString.Append(", ");
            returnString.Append(this.BottomRight.ToString(CultureInfo.CurrentCulture.NumberFormat));
            returnString.Append(", ");
            returnString.Append(this.TopLeft.ToString(CultureInfo.CurrentCulture.NumberFormat));
            returnString.Append(", ");
            returnString.Append(this.TopRight.ToString(CultureInfo.CurrentCulture.NumberFormat));

            return returnString.ToString();

        }

        /// <summary>
        /// Performs vector addition on the two specified CornerRadius objects, resulting in a new CornerRadius.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. The first CornerRadius to add.</param>
        /// <param name="cornerRadius2">CornerRadius. The second CornerRadius to add.</param>
        /// <returns>CornerRadius. A new CornerRadius that results from adding cornerRadius1 and cornerRadius2.</returns>
        public static CornerRadius Add(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return (cornerRadius1 + cornerRadius2);

        }

        /// <summary>
        /// Performs vector subtraction on the two specified CornerRadius objects, resulting in a new CornerRadius.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. The first CornerRadius to subtract.</param>
        /// <param name="cornerRadius2">CornerRadius. The second CornerRadius to subtract.</param>
        /// <returns>CornerRadius. A new CornerRadius that results from subtracting cornerRadius2 from cornerRadius1.</returns>
        public static CornerRadius Subtract(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return (cornerRadius1 - cornerRadius2);

        }

        private static int RotateLeft(int value, int bits)
        {
            bits = bits % 0x20;
            return ((value << (bits & 0x1f)) | (value >> ((0x20 - bits) & 0x1f)));

        }

        /// <summary>
        /// Performs vector addition on the two specified CornerRadius objects, resulting in a new CornerRadius.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. The first CornerRadius to add.</param>
        /// <param name="cornerRadius2">CornerRadius. The second CornerRadius to add.</param>
        /// <returns>Border. A new CornerRadius that results from adding cornerRadius1 and cornerRadius2.</returns>
        public static CornerRadius operator +(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return new CornerRadius((cornerRadius1.BottomLeft + cornerRadius2.BottomLeft), (cornerRadius1.BottomRight + cornerRadius2.BottomRight), (cornerRadius1.TopLeft + cornerRadius2.TopLeft), (cornerRadius1.TopRight + cornerRadius2.TopRight));

        }

        /// <summary>
        /// Performs vector subtraction on the two specified CornerRadius objects, resulting in a new CornerRadius.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. The first CornerRadius to subtract.</param>
        /// <param name="cornerRadius2">CornerRadius. The second CornerRadius to subtract.</param>
        /// <returns>CornerRadius. A new CornerRadius that results from subtracting cornerRadius2 from cornerRadius1.</returns>
        public static CornerRadius operator -(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return new CornerRadius(cornerRadius1.BottomLeft - cornerRadius2.BottomLeft, cornerRadius1.BottomRight - cornerRadius2.BottomRight, cornerRadius1.TopLeft - cornerRadius2.TopLeft, cornerRadius1.TopRight - cornerRadius2.TopRight);

        }

        /// <summary>
        /// Tests whether two specified CornerRadius objects are not equivalent.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. A CornerRadius to test.</param>
        /// <param name="cornerRadius2">CornerRadius. A CornerRadius to test.</param>
        /// <returns>System.Boolean . true if the two CornerRadius objects are different; otherwise, false.</returns>
        public static bool operator !=(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return !(cornerRadius1.Equals(cornerRadius2));

        }

        /// <summary>
        /// Tests whether two specified CornerRadius objects are equivalent.
        /// </summary>
        /// <param name="cornerRadius1">CornerRadius. A CornerRadius to test.</param>
        /// <param name="cornerRadius2">CornerRadius. A CornerRadius to test.</param>
        /// <returns>System.Boolean . true if the two CornerRadius objects are equivalent; otherwise, false.</returns>
        public static bool operator ==(CornerRadius cornerRadius1, CornerRadius cornerRadius2)
        {
            return cornerRadius1.Equals(cornerRadius2);

        }

    }

}
